﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.SharePoint.Administration;
using Microsoft.SharePoint;
using System.Xml;
using Microsoft.SharePoint.Utilities;
using System.Globalization;

namespace SPVSX.Explorer.Commands.SharePoint
{
    /// <summary>
    /// Custom Action Element
    /// </summary>
    public class CustomActionElement : IComparable<CustomActionElement>
    {
        #region Const Fields

        /// <summary>
        /// The control assembly attribute name
        /// </summary>
        internal const string attributeNameControlAssembly = "ControlAssembly";

        /// <summary>
        /// The control class attribute name
        /// </summary>
        internal const string attributeNameControlClass = "ControlClass";

        /// <summary>
        /// The control src attribute name
        /// </summary>
        internal const string attributeNameControlSrc = "ControlSrc";

        /// <summary>
        /// The description attribute name
        /// </summary>
        internal const string attributeNameDescription = "Description";

        /// <summary>
        /// The group id attribute name
        /// </summary>
        internal const string attributeNameGroupId = "GroupId";

        /// <summary>
        /// The id attribute name
        /// </summary>
        internal const string attributeNameId = "Id";

        /// <summary>
        /// The image url attribute name
        /// </summary>
        internal const string attributeNameImageUrl = "ImageUrl";

        /// <summary>
        /// The location attribute name
        /// </summary>
        internal const string attributeNameLocation = "Location";

        /// <summary>
        /// The registration id attribute name
        /// </summary>
        internal const string attributeNameRegistrationId = "RegistrationId";

        /// <summary>
        /// The registration type attribute name
        /// </summary>
        internal const string attributeNameRegistrationType = "RegistrationType";

        /// <summary>
        /// The require site administrator attribute name
        /// </summary>
        internal const string attributeNameRequireSiteAdmin = "RequireSiteAdministrator";

        /// <summary>
        /// The rights attribute name
        /// </summary>
        internal const string attributeNameRights = "Rights";

        /// <summary>
        /// The sequence attribute name
        /// </summary>
        internal const string attributeNameSequence = "Sequence";

        /// <summary>
        /// The show in lists attribute name
        /// </summary>
        internal const string attributeNameShowInLists = "ShowInLists";

        /// <summary>
        /// The show in read only content types attribute name
        /// </summary>
        internal const string attributeNameShowInReadOnlyContentTypes = "ShowInReadOnlyContentTypes";

        /// <summary>
        /// The show in sealed content types attribute name
        /// </summary>
        internal const string attributeNameShowInSealedContentTypes = "ShowInSealedContentTypes";

        /// <summary>
        /// The title attribute name
        /// </summary>
        internal const string attributeNameTitle = "Title";

        /// <summary>
        /// The url attribute name
        /// </summary>
        internal const string attributeNameUrl = "Url";

        /// <summary>
        /// The custom action tag name
        /// </summary>
        internal const string tagCustomAction = "CustomAction";

        /// <summary>
        /// The url action tag name
        /// </summary>
        internal const string tagUrlAction = "UrlAction";

        #endregion

        #region Properties

        /// <summary>
        /// Gets or sets the internal <see cref="SPElementDefinition"/>
        /// </summary>
        private SPElementDefinition InternalElement
        {
            get;
            set;
        }

        /// <summary>
        /// Gets the assembly of a control that supports the custom action.
        /// </summary>
        /// <remarks>Optional Text</remarks>
        public string ControlAssembly
        {
            get
            {
                return Utility.XmlGetAttributeValue(InternalElement.XmlDefinition, attributeNameControlAssembly);
            }
        }

        /// <summary>
        /// Gets the control class that supports the custom action.
        /// </summary>
        /// <remarks>Optional Text</remarks>
        public string ControlClass
        {
            get
            {
                return Utility.XmlGetAttributeValue(InternalElement.XmlDefinition, attributeNameControlClass);
            }
        }

        /// <summary>
        /// Gets the relative URL of the .ascx file that serves as the source for the custom action.
        /// </summary>
        /// <remarks>Optional Text</remarks>
        /// <example>~/_controltemplates/myCustomAction.ascx</example>
        public string ControlSrc
        {
            get
            {
                return Utility.XmlGetAttributeValue(InternalElement.XmlDefinition, attributeNameControlSrc);
            }
        }

        /// <summary>
        /// Gets the longer description for the action that is exposed as a tooltip or sub-description for the action.
        /// </summary>
        /// <remarks>Optional Text</remarks>
        public string Description
        {
            get
            {
                if (!String.IsNullOrEmpty(InternalElement.FeatureDefinition.DefaultResourceFile))
                {
                    return
                        Utility.GetLocalisedStringFromHiveResources(
                            Utility.XmlGetAttributeValue(InternalElement.XmlDefinition,
                                                         attributeNameDescription),
                            InternalElement.FeatureDefinition.DefaultResourceFile);
                }
                return
                    Utility.GetLocalisedStringFromHiveResources(
                        Utility.XmlGetAttributeValue(InternalElement.XmlDefinition,
                                                     attributeNameDescription));
            }
        }

        /// <summary>
        /// Gets the action group that contains the action. If contained within a custom action group, the value of the GroupId attribute must equal the group ID of the CustomActionGroup element.
        /// </summary>
        /// <remarks>Optional Text</remarks>
        public string GroupId
        {
            get
            {
                return Utility.XmlGetAttributeValue(InternalElement.XmlDefinition, attributeNameGroupId);
            }
        }

        /// <summary>
        /// Gets the unique identifier for the element. The ID may be a GUID, or it may be a unique term
        /// </summary>
        /// <remarks>Optional Text</remarks>
        /// <example>"SiteManagement". See Default Custom Action Locations and IDs for a list of the default custom action group IDs that are used in Windows SharePoint Services.</example>
        public string Id
        {
            get
            {
                return Utility.XmlGetAttributeValue(InternalElement.XmlDefinition, attributeNameId);
            }
        }

        /// <summary>
        /// Gets the virtual server relative link to an image that presents an icon for the item.
        /// </summary>
        /// <remarks>Optional Text</remarks>
        public string ImageUrl
        {
            get
            {
                return Utility.XmlGetAttributeValue(InternalElement.XmlDefinition, attributeNameImageUrl);
            }
        }

        /// <summary>
        /// Gets the location of this custom action.
        /// </summary>
        /// <remarks>Optional Text. If the custom action is a menu item or toolbar button, then the possible options include EditControlBlock, 
        /// NewFormToolbar, DisplayFormToolbar, and EditFormToolbar. If contained within a custom action group, the value of the Location attribute 
        /// must equal the location of the CustomActionGroup element.</remarks>
        /// <example>Microsoft.SharePoint.SiteSettings</example>
        public string Location
        {
            get
            {
                return Utility.XmlGetAttributeValue(InternalElement.XmlDefinition, attributeNameLocation);
            }
        }

        /// <summary>
        /// Gets the menu group id
        /// </summary>
        public int MenuGroupId
        {
            get
            {
                return Utility.XmlGetAttributeValueAsInt32(InternalElement.XmlDefinition, "MenuGroupId", 0x7fffffff);
            }
        }

        /// <summary>
        /// Gets the identifier of the list or item content type that this action is associated with, or the file type or programmatic identifier (ProgID).
        /// </summary>
        /// <remarks>Optional Text</remarks>
        public string RegistrationId
        {
            get
            {
                return Utility.XmlGetAttributeValue(InternalElement.XmlDefinition, attributeNameRegistrationId);
            }
        }

        /// <summary>
        /// Gets the registration attachment for a per-item action. Possible values include: ContentType FileType List ProgId
        /// </summary>
        /// <remarks>Optional Text</remarks>
        public string RegistrationType
        {
            get
            {
                return Utility.XmlGetAttributeValue(InternalElement.XmlDefinition, attributeNameRegistrationType);
            }
        }

        /// <summary>
        /// Gets the Require Site Administrator flag. TRUE to specify that the item be displayed only if the user is a site administrator; otherwise, FALSE.
        /// </summary>
        /// <remarks>Optional Boolean. Using the RequireSiteAdministrator attribute for the drop-down menu of Windows SharePoint Services commands associated with list items is not supported.</remarks>
        public bool RequireSiteAdministrator
        {
            get
            {
                return Utility.XmlGetAttributeValueAsBoolean(InternalElement.XmlDefinition, attributeNameRequireSiteAdmin);
            }
        }

        /// <summary>
        /// Gets the set of rights that the user must have in order for the link to be visible. If not specified, 
        /// then the action always appears in the list of actions. To specify multiple rights, separate the values 
        /// by using commas. The set of rights are grouped logically according to AND logic, which means that a user 
        /// must have all the specified rights to see an action. For a list of possible values, see <see cref="SPBasePermissions"/>.
        /// </summary>
        /// <remarks>Optional Text</remarks>
        /// <example>ViewListItems,ManageAlerts</example>
        public SPBasePermissions Rights
        {
            get
            {
                return Utility.XmlGetAttributeValueAsPermissions(InternalElement.XmlDefinition, attributeNameRights);
            }
        }

        /// <summary>
        /// Gets the Element tag
        /// </summary>
        public static string RootTag
        {
            get
            {
                return "CustomAction";
            }
        }

        /// <summary>
        /// Gets the ordering priority for actions.
        /// </summary>
        /// <remarks>Optional Integer</remarks>
        public int Sequence
        {
            get
            {
                return Utility.XmlGetAttributeValueAsInt32(InternalElement.XmlDefinition, attributeNameSequence, 0x7fffffff);
            }
        }
        
        /// <summary>
        /// Gets the show in lists flag
        /// </summary>
        /// <remarks>Optional Boolean</remarks>
        public bool ShowInLists
        {
            get
            {
                return Utility.XmlGetAttributeValueAsBoolean(InternalElement.XmlDefinition, attributeNameShowInLists);
            }
        }

        /// <summary>
        /// Gets the Show In Read Only ContentTypes flag TRUE if the custom action is only displayed for read-only content types on the page for managing content types. The default value is FALSE.
        /// </summary>
        /// <remarks>Optional Boolean</remarks>
        public bool ShowInReadOnlyContentTypes
        {
            get
            {
                return Utility.XmlGetAttributeValueAsBoolean(InternalElement.XmlDefinition, attributeNameShowInReadOnlyContentTypes);
            }
        }

        /// <summary>
        /// Gets the Show In Sealed ContentTypes flag TRUE if the custom action is only displayed for sealed content types on the page for managing content types. The default value is FALSE.
        /// </summary>
        /// <remarks>Optional Boolean</remarks>
        public bool ShowInSealedContentTypes
        {
            get
            {
                return Utility.XmlGetAttributeValueAsBoolean(InternalElement.XmlDefinition, attributeNameShowInSealedContentTypes);
            }
        }

        /// <summary>
        /// Gets the end user description for this action.
        /// </summary>
        /// <remarks>Optional Text</remarks>
        public string Title
        {
            get
            {
                if(!String.IsNullOrEmpty(InternalElement.FeatureDefinition.DefaultResourceFile))
                {
                    return Utility.GetLocalisedStringFromHiveResources(Utility.XmlGetAttributeValue(InternalElement.XmlDefinition,
                                                                                         attributeNameTitle), InternalElement.FeatureDefinition.DefaultResourceFile);
                }
                return Utility.GetLocalisedStringFromHiveResources(Utility.XmlGetAttributeValue(InternalElement.XmlDefinition,
                                                                                         attributeNameTitle));
            }
        }

        /// <summary>
        /// Gets the url action
        /// </summary>
        public string UrlAction
        {
            get
            {
                XmlNode xn = InternalElement.XmlDefinition.FirstChild;
                if (xn != null)
                {
                    return Utility.XmlGetAttributeValue(xn, "Url");
                }
                return null;
            }
        }

        /// <summary>
        /// Gets the server relative image url
        /// </summary>
        public string ServerRelativeImageUrl
        {
            get
            {
                return ServerRelativeUrlFromTokenizedUrl(this.ImageUrl, SPContext.Current.Web, SPContext.Current.List, SPContext.Current.Item as SPListItem);
            }
        }

        /// <summary>
        /// Gets the server relative url action
        /// </summary>
        public string ServerRelativeUrlAction
        {
            get
            {
                return ServerRelativeUrlFromTokenizedUrl(this.UrlAction, SPContext.Current.Web, SPContext.Current.List, SPContext.Current.Item as SPListItem);
            }
        }

        /// <summary>
        /// Gets or sets the permission context
        /// </summary>
        public PermissionContext PermissionContext
        {
            get; set;
        }

        /// <summary>
        /// Gets or sets the rights mode
        /// </summary>
        public PermissionMode RightsMode
        {
            get;
            set;
        }

        /// <summary>
        /// Does the user has rights
        /// </summary>
        /// <returns></returns>
        //public virtual bool UserHasRights()
        //{
        //    SASCombinedBasePermissions permissions = CurrentPermissions();
        //    SPBasePermissions emptyMask = SPBasePermissions.EmptyMask;

        //    if (PermissionContext != PermissionContext.CurrentItem)
        //    {
        //        if (PermissionContext != PermissionContext.CurrentList)
        //        {
        //            if (PermissionContext != PermissionContext.CurrentSite)
        //            {
        //                if (PermissionContext == PermissionContext.RootSite)
        //                {
        //                    emptyMask = permissions.RootSitePermissions;
        //                }
        //            }
        //            else
        //            {
        //                emptyMask = permissions.SitePermissions;
        //            }
        //        }
        //        else
        //        {
        //            emptyMask = permissions.ListPermissions;
        //        }
        //    }
        //    else
        //    {
        //        emptyMask = permissions.ListItemPermissions;
        //    }
        //    return UserHasRightsBasedOnEffectiveBasePermissions(Rights, emptyMask, RightsMode);
        //}

        //internal static SASCombinedBasePermissions CurrentPermissions()
        //{
        //    HttpContext current = HttpContext.Current;
        //    if (current.Items["sascurrentPermissions"] != null)
        //    {
        //        Type t = current.Items["sascurrentPermissions"].GetType();
        //        if(t == typeof(SASCombinedBasePermissions))
        //        {
        //            return (SASCombinedBasePermissions) current.Items["sascurrentPermissions"];
        //        }
        //    }
        //    SASCombinedBasePermissions permissions = new SASCombinedBasePermissions();
        //    current.Items["sascurrentPermissions"] = permissions;
        //    return permissions;
        //}


        //internal static bool UserHasRightsBasedOnEffectiveBasePermissions(SPBasePermissions requiredPermissions, SPBasePermissions userPermissions, PermissionMode userPermissionMode)
        //{
        //    if (userPermissionMode != PermissionMode.All)
        //    {
        //        SPBasePermissions[] permissionsArray2 = ExpandedPermissions(requiredPermissions);
        //        int index = 0;
        //        while (true)
        //        {
        //            while (index >= permissionsArray2.Length)
        //            {
        //                return false;
        //            }
        //            SPBasePermissions permissions = permissionsArray2[index];
        //            if ((permissions & userPermissions) == permissions)
        //            {
        //                return true;
        //            }
        //            index++;
        //        }
        //    }
        //    return ((requiredPermissions & userPermissions) == requiredPermissions);
        //}

        //internal static SPBasePermissions[] ExpandedPermissions(SPBasePermissions permissions)
        //{
        //    List<SPBasePermissions> list = new List<SPBasePermissions>();
        //    for (SPBasePermissions permissions2 = SPBasePermissions.EmptyMask | SPBasePermissions.ViewListItems; permissions2 != SPBasePermissions.EmptyMask; permissions2 = (SPBasePermissions)(((ulong)permissions2) << 1))
        //    {
        //        if ((permissions & permissions2) != SPBasePermissions.EmptyMask)
        //        {
        //            list.Add(permissions2);
        //        }
        //    }
        //    return list.ToArray();
        //}





        #endregion

        #region Methods

        /// <summary>
        /// Create a new CustomActionElement object
        /// </summary>
        /// <param name="element">The <see cref="SPElementDefinition"/> object</param>
        public CustomActionElement(SPElementDefinition element)
        {
            InternalElement = element;

            //Configure some other defaults
            RightsMode = PermissionMode.Any;
            PermissionContext = PermissionContext.CurrentSite;
        }

        /// <summary>
        /// Compare which uses the Sequence property
        /// </summary>
        /// <param name="caOtherGroup">The <see cref="CustomActionElement"/> under comparison</param>
        /// <returns>The result of the comparison</returns>
        int IComparable<CustomActionElement>.CompareTo(CustomActionElement caOtherGroup)
        {
            int sequence = caOtherGroup.Sequence;
            return (Sequence - sequence);
        }

        
        
        #endregion



       

        

        private string GetServerRelativeImageUrlForWebListItem(SPWeb web, SPList list, SPListItem listItem)
        {
            return ServerRelativeUrlFromTokenizedUrl(this.ImageUrl, web, list, listItem);
        }

        private string GetServerRelativeUrlActionForWebListItem(SPWeb web, SPList list, SPListItem listItem)
        {
            return ServerRelativeUrlFromTokenizedUrl(this.UrlAction, web, list, listItem);
        }

       

        private static string ReplaceUrlTokens(string actionUrl, SPWeb web, SPList list, SPListItem item)
        {
            string recurrenceID;
            if (!string.IsNullOrEmpty(actionUrl))
            {
                if (item == null)
                {
                    if (web != null)
                    {
                        actionUrl = actionUrl.Replace("{SiteUrl}", web.Url);
                    }
                    if (list != null)
                    {
                        actionUrl = actionUrl.Replace("{ListId}", list.ID.ToString("B"));
                    }
                    actionUrl = SPUtility.GetServerRelativeUrlFromPrefixedUrl(actionUrl);
                    return actionUrl;
                }
                string newValue = item.ID.ToString(CultureInfo.InvariantCulture);
                actionUrl = actionUrl.Replace("{ItemId}", newValue);
                actionUrl = actionUrl.Replace("{ItemUrl}", item.Url);
                recurrenceID = newValue;
                if (!string.IsNullOrEmpty(item.RecurrenceID))
                {
                    recurrenceID = item.RecurrenceID;
                }
            }
            else
            {
                return actionUrl;
            }
            actionUrl = actionUrl.Replace("{RecurrenceId}", recurrenceID);
            if (web != null)
            {
                actionUrl = actionUrl.Replace("{SiteUrl}", web.Url);
            }
            if (list != null)
            {
                actionUrl = actionUrl.Replace("{ListId}", list.ID.ToString("B"));
            }
            actionUrl = SPUtility.GetServerRelativeUrlFromPrefixedUrl(actionUrl);
            return actionUrl;
        }

        private static string ServerRelativeUrlFromTokenizedUrl(string sTokenizedUrl, SPWeb web, SPList list, SPListItem listItem)
        {
            string str = ReplaceUrlTokens(sTokenizedUrl, web, list, listItem);
            if (string.IsNullOrEmpty(str))
            {
                return str;
            }
            if (Utility.IsAbsoluteUrl(str))
            {
                return str;
            }
            if (str[0] == '/')
            {
                return str;
            }
            if (web == null)
            {
                return str;
            }
            string serverRelativeUrl = web.ServerRelativeUrl;
            if (!serverRelativeUrl.EndsWith("/"))
            {
                serverRelativeUrl = serverRelativeUrl + "/";
            }
            return (serverRelativeUrl + str);
        }

        

        private bool ValidControlAttributes()
        {
            bool flag = true;
            if (!(string.IsNullOrEmpty(this.ControlAssembly) || string.IsNullOrEmpty(this.ControlClass)))
            {
                if (string.IsNullOrEmpty(this.ControlAssembly))
                {
                    return flag;
                }
                return (string.IsNullOrEmpty(this.ControlSrc) && flag);
            }
            return false;
        }

        
    }
}

